﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;

namespace XwingGame
{
    public class Bee
    {
        private XwingGame game;
        private Model model;
        private int leftWing1; 
        private int rightWing1; 
        private int leftWing2; 
        private int rightWing2;
        private float wingAngle = 0;
        private float wingSpeed = 10;
        private bool wingUp = true;
        private bool animate = false;
        int beeState = 0;
        float flyTime = 0;
        float speed = 1000;


        /// <summary>
        /// Ship orientation as a quaternion
        /// </summary>
        Quaternion orientation = Quaternion.Identity;
        

        /// <summary>
        /// Current position
        /// </summary>
        private Vector3 position = Vector3.Zero;

        /// <summary>
        /// Thrust in cm/sec^2
        /// </summary>
        private float thrust;

        /// <summary>
        /// Decelleration due to drag
        /// </summary>
        private float drag = 0.5f;

        /// <summary>
        /// Maximum thrust (cm/sec^2)
        /// </summary>
        private const float MaxThrust = 2940;

        /// <summary>
        /// The current turning rate in radians per scond
        /// Effectively the asimuth change rate
        /// </summary>
        private float turnRate = 0;

        /// <summary>
        /// The maximum turning rate
        /// </summary>
        private const float MaxTurnRate = (float)Math.PI;

        /// <summary>
        /// Elevation change rate
        /// </summary>
        private float pitchRate = 0;

        /// <summary>
        /// The max elevation change rate
        /// </summary>
        private const float MaxPitchRate = (float)Math.PI / 2;

        /// <summary>
        /// Current Bank Angle in rads
        /// </summary>
        private float rollAngle = 0;

        /// <summary>
        /// Current Bank Speed in rads/sec
        /// </summary>
        private float rollSpeed = 0;

        /// <summary>
        /// Max Bank Speed in rads/sec
        /// </summary>
        private const float MaxRollSpeed = (float)Math.PI / 2;

        public Model Model { get { return model; } }
        public float TurnRate { get { return turnRate; } set { turnRate = value; } }
        public float Thrust { get { return thrust; } set { thrust = value; } }
        public Vector3 Position { get { return position; } set { position = value; } }
        public float PitchRate { get { return pitchRate; } set { pitchRate = value; } }
        public float RollSpeed { get { return rollSpeed; } set { rollSpeed = value; } }
        public float RollAngle { get { return rollAngle; } set { rollAngle = value; } }
        public bool Animate { get { return animate; } set { animate = value; } }
        public Matrix Transform
        {
            get
            {
                return
                    Matrix.CreateFromQuaternion(orientation) *
                    Matrix.CreateTranslation(position);
            }
        }


        public Bee(XwingGame game)
        {
            this.game = game;
        }

        /// <summary>
        /// This funcion is called to load content into this component
        /// of our game.
        /// </summary>
        /// <param name="content"> The content manager to load from. </param>
        public void LoadContent(ContentManager content)
        {
            model = content.Load<Model>("Bee");
            leftWing1 = model.Bones.IndexOf(model.Bones["LeftWing1"]);
            rightWing1 = model.Bones.IndexOf(model.Bones["RightWing1"]);
            leftWing2 = model.Bones.IndexOf(model.Bones["LeftWing2"]);
            rightWing2 = model.Bones.IndexOf(model.Bones["RightWing2"]);

        }


        /// <summary>
        /// This function is called to update this component of our game
        /// to the current game time.
        /// </summary>
        /// <param name="gameTime"> current game time </param>
        public void Update(GameTime gameTime)
        {
            float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (wingUp)
            {
                wingAngle += wingSpeed * delta;
            }
            else
            {
                wingAngle -= wingSpeed * delta;
            }

            if (wingAngle > 1.134f || wingAngle < 0f)
                wingUp = !wingUp;

            if (!animate)
                wingAngle = 0;
            //
            // Orientation updates
            //            
            orientation *= Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), turnRate * MaxTurnRate * delta);
            orientation *= Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), pitchRate * MaxPitchRate * delta);
            orientation *= Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), rollSpeed * MaxRollSpeed * delta);
            orientation.Normalize();

            //
            // Position updates
            //

            Matrix transform = Matrix.CreateFromQuaternion(orientation);
            Vector3 directedThrust = Vector3.Zero;
            if (animate)
            {
                if (beeState == 0)
                {
                    directedThrust = Vector3.TransformNormal(new Vector3(0, 0, 1), transform);
                    if (flyTime > 5)
                    {
                        beeState = 1;
                        flyTime = 0;
                    }
                }
                if (beeState == 1)
                {
                    directedThrust = Vector3.TransformNormal(new Vector3(0, 0, -1), transform);
                    if (flyTime > 5)
                    {
                        beeState = 0;
                        flyTime = 0;
                    }
                }

                flyTime += delta;
                position += directedThrust * speed * delta;

            }

            System.Diagnostics.Trace.WriteLine(position.ToString());

        }


        /// <summary>
        /// This function is called to draw this game component.
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="gameTIme"><</param>
        public void Draw(GraphicsDeviceManager graphics, GameTime gameTime)
        {
            DrawModel(graphics, model, Transform);
        }

        private void DrawModel(GraphicsDeviceManager graphics, Model model, Matrix world)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            transforms[rightWing1] = Matrix.CreateRotationY(wingAngle) * transforms[rightWing1];
            transforms[leftWing1] = Matrix.CreateRotationY(-wingAngle) * transforms[leftWing1];
            transforms[rightWing2] = Matrix.CreateRotationY(wingAngle) * transforms[rightWing2];
            transforms[leftWing2] = Matrix.CreateRotationY(-wingAngle) * transforms[leftWing2];


            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(200f) * world;
                    effect.View = game.Camera.View;
                    effect.Projection = game.Camera.Projection;                    
                }
                mesh.Draw();
            }
        }
    }
}
